﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using JelleDruyts.Windows;
using Schedulr.Messages;
using Schedulr.Models;
using Schedulr.ViewModels;

namespace Schedulr.Infrastructure
{
    public class BatchIdGroupDescription : GroupDescription
    {
        private Account account;
        private IList<Picture> pictures;
        private IDictionary<int, BatchHeader> batchHeaders = new Dictionary<int, BatchHeader>();

        public BatchIdGroupDescription(Account account, IList<Picture> pictureList)
        {
            this.account = account;
            this.pictures = pictureList;
            Messenger.Register<UploadScheduleChangedMessage>(OnUploadScheduleChanged);
            Messenger.Register<PictureQueueChangedMessage>(OnPictureQueueChanged);
            RefreshBatchHeaders();
        }

        private void RefreshBatchHeaders()
        {
            if (this.pictures == null || this.pictures.Count == 0)
            {
                this.batchHeaders.Clear();
            }
            else
            {
                IList<DateTime> nextRunTimes = null;
                var pictureBatches = this.pictures.GroupBy(p => p.BatchId).ToList();
                foreach (var pictureBatch in pictureBatches)
                {
                    var batchId = pictureBatch.Key;
                    var totalPicturesInBatch = pictureBatch.Count();

                    // If no proper batch name could be constructed, just return a generic batch number.
                    var longName = "Batch " + batchId;
                    var shortName = longName;

                    if (pictureBatch.All(p => p.DateUploaded.HasValue))
                    {
                        // These pictures have already been uploaded, name the batch according to the uploaded date.
                        // Assume that they have all been uploaded at the same time.
                        var uploaded = pictureBatch.First().DateUploaded.Value;
                        longName = "Uploaded on " + uploaded.ToString("f");
                        shortName = uploaded.ToShortDateString();
                    }
                    else
                    {
                        if (nextRunTimes == null)
                        {
                            nextRunTimes = ScheduledTaskClient.GetNextRunTimesForAccount(this.account, pictureBatches.Count);
                        }
                        if (nextRunTimes.Count >= batchId)
                        {
                            var runTime = nextRunTimes[batchId - 1];
                            longName += string.Format(CultureInfo.CurrentCulture, " - Scheduled for {0}", runTime.ToString("f"));
                            shortName = runTime.ToShortDateString();
                        }
                    }
                    longName += totalPicturesInBatch.ToCountString("file", " (", ")");
                    shortName += string.Format(CultureInfo.CurrentCulture, " ({0})", totalPicturesInBatch);

                    if (!this.batchHeaders.ContainsKey(batchId))
                    {
                        // There is no batch header for this batch yet, create a new one.
                        var isExpanded = true;
                        // TODO: Only expand the first few batches since it has a significant performance impact to expand large numbers of batches.
                        //isExpanded = (batchId <= 10); // TODO: Make configurable?
                        var batchHeader = new BatchHeader(batchId, longName, shortName, isExpanded);
                        this.batchHeaders.Add(batchId, batchHeader);
                    }
                    else
                    {
                        // Update an existing batch header with the new names (but keep the expanded state).
                        // TODO: Remember expanded state across application restarts.
                        var batchHeader = this.batchHeaders[batchId];
                        batchHeader.LongName = longName;
                        batchHeader.ShortName = shortName;
                    }
                }
            }
        }

        private void OnPictureQueueChanged(PictureQueueChangedMessage message)
        {
            RefreshGroupNames();
        }

        private void OnUploadScheduleChanged(UploadScheduleChangedMessage message)
        {
            RefreshGroupNames();
        }

        private void RefreshGroupNames()
        {
            RefreshBatchHeaders();
            this.OnPropertyChanged(new PropertyChangedEventArgs("GroupNames"));
        }

        public override object GroupNameFromItem(object item, int level, CultureInfo culture)
        {
            var picture = ((PictureViewModel)item).Picture;
            var batchId = picture.BatchId;
            if (this.batchHeaders.ContainsKey(batchId))
            {
                return this.batchHeaders[batchId];
            }
            else
            {
                var name = "Batch " + batchId;
                return new BatchHeader(batchId, name, name, false);
            }
        }

        public void SetBatchesExpanded(bool expanded)
        {
            foreach (BatchHeader batchHeader in this.batchHeaders.Values)
            {
                batchHeader.IsExpanded = expanded;
            }
        }
    }
}